﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Web.Security;
using System.Data.SqlClient;



namespace WCF
{
    public class GeekMeetService : IGeekMeetService
    {

        /// <summary>
        /// Creates a new private message and saves it.
        /// </summary>
        /// <param name="fromID">The Guid of the sender</param>
        /// <param name="toID">The Guid of the reciever</param>
        /// <param name="message">String with message</param>
        /// <returns>True if success</returns>
        public bool SendMessage(System.Guid fromID, System.Guid toID, string message)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    Message m = new Message();
                    m.MessageText = message;
                    m.FromID = fromID;
                    m.ToID = toID;
                    m.PostDate = DateTime.Now;
                    db.Message.AddObject(m);
                    db.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Deletes a specified user from the database
        /// </summary>
        /// <param name="userID">The user to be deleted</param>
        /// <returns>True if success</returns>
        public bool DeleteUser(Guid userID)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    //Selects the user from db
                    var user = (from n in db.aspnet_Users
                                where n.UserId == userID
                                select n).Single();

                    db.aspnet_Users.DeleteObject(user);
                    db.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Deletes a specified message from the database. 
        /// </summary>
        /// <param name="msgID">Message to be deleted.</param>
        /// <returns>True if success</returns>
        public bool DeleteMessage(int msgID)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    Message m = (from n in db.Message
                                 where n.MessageID == msgID
                                 select n).Single();

                    db.Message.DeleteObject(m);
                    db.SaveChanges();
                    return true;
                }
                catch {
                    return false;
                }
            }
        }

        /// <summary>
        /// Gets the profiles of the users that has sent private messages to the logged in user
        /// </summary>
        /// <param name="userID"></param>
        /// <returns>List of FriendComposite objects</returns>
        public List<FriendComposite> GetConversationContacts(System.Guid userID)
        {
            List<FriendComposite> friendsList = new List<FriendComposite>();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                var result = db.sp_getConversationContacts(userID.ToString());

                foreach (var friend in result)
                {
                    FriendComposite addFriend = new FriendComposite();
                    addFriend.UserID = friend.UserID.Value;
                    addFriend.UserName = friend.UserName;

                    friendsList.Add(addFriend);

                }

                return friendsList;

            }
        }

        /// <summary>
        /// Gets the conversation between 2 users, all private messages between them.
        /// </summary>
        /// <param name="user1">Guid of one user</param>
        /// <param name="user2">Guid of the second user</param>
        /// <returns>A list of MessageComposite objects with info about all the messages.</returns>
        public List<MessageComposite> GetConversation(System.Guid user1, System.Guid user2)
        {
            List<MessageComposite> messages = new List<MessageComposite>();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var conv = (from n in db.Message
                                join users in db.aspnet_Users
                                on n.FromID equals users.UserId
                                where (n.FromID == user1 && n.ToID == user2)
                                || (n.ToID == user1 && n.FromID == user2)
                                orderby n.PostDate
                                select new
                                {
                                    n.MessageID,
                                    n.FromID,
                                    n.ToID,
                                    n.PostDate,
                                    n.MessageText,
                                    users.UserName
                                });

                    foreach (var message in conv)
                    {
                        MessageComposite addMessage = new MessageComposite();
                        addMessage.FromID = message.FromID.Value;
                        addMessage.ToID = message.ToID.Value;
                        addMessage.MessageText = message.MessageText;
                        addMessage.PostDate = message.PostDate.Value;
                        addMessage.FromUserName = message.UserName;

                        messages.Add(addMessage);
                    }
                    return messages;
                }
                catch {
                    return null;
                }
                
            }
        }

        /// <summary>
        /// Creates a new profile for a user
        /// </summary>
        /// <param name="user">The Guid of the user</param>
        /// <returns>True if success</returns>
        public bool CreateNewProfile(System.Guid user)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    Profile pn = new Profile();
                    pn.UserID = user;
                    pn.Gender = "m";
                    db.Profile.AddObject(pn);
                    db.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Finds a users profile from username
        /// </summary>
        /// <param name="username">Username of the user to be found</param>
        /// <returns>A ProfileComposite object with id and name</returns>
        public ProfileComposite FindUser(string username)
        {
            ProfileComposite p = new ProfileComposite();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var user = (from n in db.aspnet_Users
                                where n.UserName == username
                                select new { 
                                    n.UserName, 
                                    n.UserId }
                                    ).FirstOrDefault();
                    if (user != null)
                    {

                        p.UserID = user.UserId;
                        p.Username = user.UserName;
                    }
                    return p;
                }
                catch {
                    return null;
                }
            }
            
        }

        /// <summary>
        /// Gets a users profile based on guid.
        /// </summary>
        /// <param name="user">Guid of user to get</param>
        /// <returns>Profilecomposite object with the specified attributes, null if fail</returns>
        public ProfileComposite GetProfile(System.Guid user)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var dbProfile = (from profile in db.Profile
                                     join u in db.aspnet_Users
                                     on (Guid)profile.UserID equals (Guid)u.UserId
                                     where u.UserId == user
                                     select new
                                     {
                                         profile.BirthDate,
                                         profile.FirstName,
                                         profile.IsVisible,
                                         profile.IsPremium,
                                         profile.LastName,
                                         profile.PremiumExpireDate,
                                         profile.Text,
                                         profile.City,
                                         profile.Country,
                                         profile.Gender,
                                         u.UserName,
                                         u.UserId
                                     }
                                     ).Single();

                    ProfileComposite p = new ProfileComposite();
                    p.UserID = dbProfile.UserId;
                    p.FirstName = (dbProfile.FirstName == null) ? "" : dbProfile.FirstName;
                    p.LastName = (dbProfile.LastName == null) ? "" : dbProfile.LastName;
                    p.BirthDate = (dbProfile.BirthDate.HasValue) ? dbProfile.BirthDate.Value : new DateTime(1977, 01, 01);
                    p.PremiumExpireDate = dbProfile.PremiumExpireDate.GetValueOrDefault(new DateTime(1901, 01, 01));
                    p.IsVisible = dbProfile.IsVisible;
                    p.IsPremium = dbProfile.IsPremium;
                    p.Text = (dbProfile.Text == null) ? "" : dbProfile.Text;
                    p.City = dbProfile.City;
                    p.Country = dbProfile.Country;
                    p.Username = dbProfile.UserName;
                    p.Gender = dbProfile.Gender;
                    return p;
                }
                catch {
                    return null;
                }
            }
        }

        /// <summary>
        /// Edits a users profile
        /// </summary>
        /// <param name="p">Profile to be edited</param>
        /// <returns>True if success</returns>
        public bool EditProfile(ProfileComposite p)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    Profile savedProfile = (from n in db.Profile
                                            where n.UserID == p.UserID
                                            select n).Single();

                    savedProfile.BirthDate = p.BirthDate;
                    savedProfile.FirstName = p.FirstName;
                    savedProfile.LastName = p.LastName;
                    savedProfile.Text = p.Text;
                    savedProfile.City = p.City;
                    savedProfile.Country = p.Country;
                    savedProfile.Gender = p.Gender;

                    db.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }

            }

        }

        /// <summary>
        /// Gets all stored interests in the database
        /// </summary>
        /// <returns>A list of interestcomposite objects, null if fail</returns>
        public List<InterestComposite> GetAllInterests()
        {
            List<InterestComposite> interests = new List<InterestComposite>();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var result = (from i in db.Interest
                                  select i).OrderBy(i => i.Name);

                    foreach (var interest in result)
                    {
                        InterestComposite i = new InterestComposite();
                        i.InterestID = interest.InterestID;
                        i.InterestName = interest.Name;

                        interests.Add(i);
                    }

                    return interests;
                }
                catch
                {
                    return null;
                }
            }

        }

        /// <summary>
        /// Gets all interest that a specific user has selected. 
        /// </summary>
        /// <param name="userId">Guid of user to select interests from</param>
        /// <returns>A list if Interestcompositeobjects, null if fail</returns>
        public List<InterestComposite> GetUserInterests(System.Guid userId)
        {
            List<InterestComposite> interests = new List<InterestComposite>();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var result = (from n in db.UserInterest
                                  join i in db.Interest
                                  on n.InterestID equals i.InterestID
                                  where n.UserID == userId
                                  select new
                                  {
                                      i.InterestID,
                                      i.Name
                                  });


                    foreach (var i in result)
                    {
                        InterestComposite interest = new InterestComposite();
                        interest.InterestID = i.InterestID;
                        interest.InterestName = i.Name;
                        interests.Add(interest);
                    }
                    return interests;
                }
                catch
                {
                    return null;
                }
            }
            
        }

        /// <summary>
        /// Creates a new interest and adds it to the database
        /// </summary>
        /// <param name="interestname">Name of the interest to add</param>
        /// <returns>True on success</returns>
        public bool CreateNewInterest(string interestname)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {

                    Interest i = new Interest();
                    i.Name = interestname;
                    db.Interest.AddObject(i);
                    db.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Modifies a users interestlist
        /// </summary>
        /// <param name="whichUserID"></param>
        /// <param name="interests"></param>
        /// <returns>True on success</returns>
        public bool ModifyUserInterests(System.Guid whichUserID, IEnumerable<int> interests)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    //Gets the interests currently stored
                    var storedUserInterests = (from n in db.UserInterest
                                               where n.UserID == whichUserID
                                               select n);
                    
                    foreach (int i in interests)
                    {
                        //Checks if the interests in the argument list is already stored using a lambda expression
                        UserInterest ui = (UserInterest)storedUserInterests.FirstOrDefault(x => x.InterestID == i);
                        if (ui == null)
                        {
                            //If not - store it
                            UserInterest newInterest = new UserInterest();
                            newInterest.InterestID = i;
                            newInterest.UserID = whichUserID;
                            db.UserInterest.AddObject(newInterest);
                        }
                    }

                    foreach (UserInterest i in storedUserInterests)
                    {
                        int id = interests.FirstOrDefault(x => x == i.InterestID);

                        if (id == 0)
                            db.DeleteObject(i);
                    }

                    db.SaveChanges();
                    return true;
                }
                catch 
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Removes an interest from a user
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="interestID">ID of the interest to be removed</param>
        /// <returns>True if success</returns>
        public bool RemoveInterestFromUser(System.Guid userID, int interestID)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    UserInterest ui = (from n in db.UserInterest
                                       where n.UserID == userID && n.InterestID == interestID
                                       select n).Single();
                    db.UserInterest.DeleteObject(ui);
                    db.SaveChanges();
                    return true;
                }
                catch {
                    return false;
                }
            }
        }

        /// <summary>
        /// Makes a friend connection request between 2 users - not yet seen and confirmed by target user
        /// </summary>
        /// <param name="requestuserID"></param>
        /// <param name="targetuserID"></param>
        /// <param name="friendCategory"></param>
        /// <returns>True if success</returns>
        public bool BeFriends(System.Guid requestuserID, System.Guid targetuserID, int friendCategory)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    Friend f = new Friend();
                    f.RequestFromID = requestuserID;
                    f.RequestToID = targetuserID;
                    f.IsApproved = false;
                    f.IsSeen = false;
                    f.IsConfirmed = false;
                    f.FriendCategory = friendCategory;
                    db.Friend.AddObject(f);
                    db.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Removes a friend connection between 2 users
        /// </summary>
        /// <param name="requestuserID"></param>
        /// <param name="targetuserID"></param>
        /// <returns>True if success</returns>
        public bool UnFriend(System.Guid requestuserID, System.Guid targetuserID)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    // Find a match in both columns
                    Friend f = (from n in db.Friend
                                where n.RequestFromID == requestuserID && n.RequestToID == targetuserID ||
                                n.RequestFromID == targetuserID && n.RequestToID == requestuserID
                                select n).Single();
                    db.Friend.DeleteObject(f);

                    db.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Lets a user confirm a friend connection that has been sent
        /// </summary>
        /// <param name="RequestFromID"></param>
        /// <param name="RequestToID"></param>
        /// <param name="IsAccepted">Boolean that tells if the request has been accepted</param>
        /// <returns>True on success</returns>
        public bool ConfirmFriend(Guid RequestFromID, Guid RequestToID, bool IsAccepted)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var friendship = (from f in db.Friend
                                 where f.RequestFromID == RequestFromID
                                 && f.RequestToID == RequestToID
                                 select f).SingleOrDefault();

                    friendship.IsApproved = IsAccepted;
                    friendship.IsSeen = true;
                    friendship.IsConfirmed = true;
                
                    db.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }

            }

        }

        /// <summary>
        /// Gets the city from a user
        /// </summary>
        /// <param name="userID"></param>
        /// <returns>string with city name</returns>
        public string GetCity(Guid userID)
        {

            using (GeekMeetEntities db = new GeekMeetEntities())
            {

                return (from n in db.Profile
                                      where n.UserID == userID
                                      select n.City).SingleOrDefault();
            }
        }

        /// <summary>
        /// Gets the age for a user
        /// </summary>
        /// <param name="userID"></param>
        /// <returns>string with age</returns>
        public string GetAge(Guid userID)
        {
            string age;

            using (GeekMeetEntities db = new GeekMeetEntities())
            {

                DateTime birthdate = (from n in db.Profile
                                      where n.UserID == userID
                                      select n.BirthDate).SingleOrDefault().Value;

                age = (DateTime.Now.Year - birthdate.Year).ToString();
                
                return age;
            }
        }
    
        /// <summary>
        /// Gets the gender on a user
        /// </summary>
        /// <param name="userID"></param>
        /// <returns>String that tells what gender user is</returns>
        public string GetGender(Guid userID)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {

                return (from n in db.Profile
                             where n.UserID == userID
                             select n.Gender).SingleOrDefault().ToString() ;
            }
        }

        /// <summary>
        /// Gets the friends of a specific user
        /// </summary>
        /// <param name="requestuserID"></param>
        /// <returns>List of FriendComposite objects</returns>
        public List<FriendComposite> GetFriends(System.Guid requestuserID)
        {
            List<FriendComposite> friendsList = new List<FriendComposite>();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    //Calls on a stored procedure in database that returns a collection of friends
                    var result = db.sp_getFriends(requestuserID.ToString());

                    foreach (var friend in result)
                    {
                        FriendComposite addFriend = new FriendComposite();
                        addFriend.UserID = friend.UserID;
                        addFriend.UserName = friend.UserName;
                        addFriend.FriendCategoryName = friend.CategoryName;

                        friendsList.Add(addFriend);
                    }
                    return friendsList;
                }
                catch {
                    return null;
                }

            }
           
        }

        /// <summary>
        /// Creates a new wallpost 
        /// </summary>
        /// <param name="fromuserID"></param>
        /// <param name="touserID"></param>
        /// <param name="msg"></param>
        /// <returns>True on success</returns>
        public bool CreateWallPost(System.Guid fromuserID, System.Guid touserID, string msg)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    Wall w = new Wall();
                    w.FromID = fromuserID;
                    w.ToID = touserID;
                    w.Message = msg;
                    w.PostDate = DateTime.Now;
                    db.Wall.AddObject(w);
                    db.SaveChanges();
                    return true;
                }
                catch {
                    return false;
                }
            }
        }

        /// <summary>
        /// Removes a specific wallpost
        /// </summary>
        /// <param name="msgID"></param>
        /// <returns>True on success</returns>
        public bool RemoveWallPost(int msgID)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                //Checks if a message with msgID exists
                if (db.Wall.Any(u => u.MessageID == msgID))
                {
                    Wall w = (from n in db.Wall
                              where n.MessageID == msgID
                              select n).Single();
                    db.Wall.DeleteObject(w);
                    db.SaveChanges();
                    return true;
                }
                return false;
            }
        }

        /// <summary>
        /// Sets the status of is seen messages to seen. 
        /// </summary>
        /// <param name="fromUser"></param>
        /// <param name="toUser"></param>
        /// <returns>true on success</returns>
        public bool SetMessagesIsRead(Guid fromUser, Guid toUser)
        {
            try
            {
                using (GeekMeetEntities db = new GeekMeetEntities())
                {
                    //selects the unread messages from/to the specified user
                    var messages = from n in db.Message
                                       where (n.IsSeen == false)
                                       && (n.FromID == fromUser &&
                                             n.ToID == toUser)
                                       select n;

                    //sets the isseen property to seen on all unread messages using lambda syntax
                    messages.ToList().ForEach(x => x.IsSeen = true);
                    db.SaveChanges();

                    return true;
                }
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Sets unread wallmessages to read
        /// </summary>
        /// <returns>true on success</returns>
        public bool SetWallMessagesIsRead()
        {
            try
            {
                using (GeekMeetEntities db = new GeekMeetEntities())
                {
                    //Get unseen wallposts
                    var wallmessages = from n in db.Wall
                                       where (!n.IsSeen)
                                       select n;

                    //Set isseen property to true
                    wallmessages.ToList().ForEach(x => x.IsSeen = true);
                    db.SaveChanges();

                    return true;
                }
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Gets all wallposts that has been sent to a specific user
        /// </summary>
        /// <param name="userID"></param>
        /// <returns>A list of WallComposite objects</returns>
        public List<WallComposite> GetWallPosts(System.Guid userID)
        {
            List<WallComposite> wallPosts = new List<WallComposite>();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    //Selects all wallposts and userID on who sent them to a specific user
                    var wallTable = (from n in db.Wall

                                     join users in db.aspnet_Users
                                     on n.FromID equals users.UserId
                                     orderby n.PostDate descending
                                     where n.ToID == userID
                                     select new
                                     {
                                         n.ToID,
                                         n.Message,
                                         n.MessageID,
                                         n.PostDate,
                                         n.FromID,
                                         users.UserName
                                     });

                    //Loop through the collection from the database and create WallComposite objects
                    //that stores all information
                    foreach (var w in wallTable)
                    {
                        WallComposite wc = new WallComposite();
                        wc.FromID = w.FromID.Value;
                        wc.ToID = w.ToID.Value;
                        wc.MessageID = w.MessageID;
                        wc.MessageText = w.Message;
                        wc.PostDate = w.PostDate.Value;
                        wc.FromUserName = w.UserName;

                        wallPosts.Add(wc);
                    }
                    return wallPosts;
                }
                catch
                {
                    return null;
                }

            }
            
        }

        /// <summary>
        /// Changes the isVisible state of a specific user, which determines if the user
        /// is visible in searches.
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="state">True or false depending on the users request</param>
        /// <returns>True on success</returns>
        public bool ToggleInvisibleState(Guid userID, bool state)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var p = (from profiles in db.Profile
                             where profiles.UserID == userID
                             select profiles).Single();

                    p.IsVisible = state;
                    db.SaveChanges();

                    return true;
                }
                catch {
                    return false;
                }
            }
        }

        /// <summary>
        /// Checks if a friend request is accepted
        /// </summary>
        /// <param name="user1"></param>
        /// <param name="user2"></param>
        /// <returns>True if request is accepted</returns>
        public bool IsFriendAccepted(Guid user1, Guid user2)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                //hm, inte helt hundra på vad som händer här
                var result = (from n in db.Friend
                              where (n.RequestFromID == user1
                                      && n.RequestToID == user2)
                                     || (n.RequestFromID == user2
                                          && n.RequestToID == user1)
                                     && n.IsConfirmed
                              select n).SingleOrDefault();

                if (result != null && result.IsApproved)
                    return true;
                else
                    return false;

            }
        }

        /// <summary>
        /// Checks if the specific user has sent a request to the profile he is visiting
        /// </summary>
        /// <param name="user1"></param>
        /// <param name="user2"></param>
        /// <returns>Guid of the user that has sent the request</returns>
        public Guid GetFriendRequester(Guid user1, Guid user2)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                var result = (from n in db.Friend
                              where (n.RequestFromID == user1
                                      && n.RequestToID == user2)
                                     || (n.RequestFromID == user2
                                          && n.RequestToID == user1)
                                     
                              select n).FirstOrDefault();

                if (result != null)
                    return result.RequestFromID;
                else
                    return new Guid();
            }
        
        
        }

        /// <summary>
        /// Checks if two users has a friend request between them
        /// </summary>
        /// <param name="user1"></param>
        /// <param name="user2"></param>
        /// <returns>True if there is a request</returns>
        public bool IsFriendRequested(Guid user1, Guid user2)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var result = (from n in db.Friend
                                  where (n.RequestFromID == user1
                                          && n.RequestToID == user2)
                                         || (n.RequestFromID == user2
                                              && n.RequestToID == user1)

                                  select n);

                    if (result.Any())
                        return true;
                    else
                        return false;
                }
                catch
                {
                    return false;
                }
            } 
        }

        /// <summary>
        /// ????
        /// </summary>
        /// <param name="user1"></param>
        /// <param name="user2"></param>
        /// <returns></returns>
        public bool IsFriendRequestPending(Guid user1, Guid user2)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var result = (from n in db.Friend
                                  where ((n.RequestFromID == user1
                                          && n.RequestToID == user2)
                                         || (n.RequestFromID == user2
                                              && n.RequestToID == user1))
                                       && (n.IsConfirmed == false) && (n.IsApproved == false)
                                  select n).FirstOrDefault();

                    if (result != null)
                        return true;
                    else
                        return false;
                }
                catch
                {
                    return false;
                }

            }     
        }

        /// <summary>
        /// Gets the new friend requests to a user, that he has not yet seen
        /// </summary>
        /// <param name="userID"></param>
        /// <returns>An IEnumerable collection of FriendComposite objects</returns>
        public IEnumerable<FriendComposite> GetNewFriends(Guid userID)
        {
            List<FriendComposite> newFriends = new List<FriendComposite>();
            
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    //select all friendrequests to a user that has not been seen and not approved
                    var result = (from n in db.Friend
                                  join u in db.aspnet_Users
                                  on n.RequestFromID equals u.UserId
                                  join p in db.Profile
                                  on n.RequestFromID equals p.UserID
                                  join fc in db.FriendCategory
                                  on n.FriendCategory equals fc.CategoryID
                                  where (n.RequestToID == userID)
                                  && (!n.IsSeen) && (!n.IsApproved)
                                  select new { u.UserId, u.UserName, p.FirstName, p.LastName, fc.CategoryName })
                                      .Distinct();

                    foreach (var friend in result)
                    {
                        if (friend.UserId != userID)
                        {
                            FriendComposite f = new FriendComposite();
                            f.FirstName = friend.FirstName;
                            f.LastName = friend.LastName;
                            f.UserName = friend.UserName;
                            f.UserID = friend.UserId;
                            f.FriendCategoryName = friend.CategoryName;

                            newFriends.Add(f);
                        }
                    }
                    return newFriends;
                }
                catch
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// Gets the notifications to a user, that tells if he has new messages, 
        /// new friendrequests or new wallposts
        /// </summary>
        /// <param name="userID"></param>
        /// <returns>An IDictionary collection, with the string 'Messages', 'Friends' 
        /// or 'WallMessages' as key, and a boolean value that tells if there 
        /// are any new requests.</returns>
        public IDictionary<string, bool> GetNotifications(Guid userID)
        {
            Dictionary<string, bool> toReturn = new Dictionary<string, bool>();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                var newfriends = (from n in db.Friend
                                  where n.RequestToID == userID
                                  && (!n.IsSeen) && (!n.IsApproved)
                                  select n).FirstOrDefault();

                var newWallMessages = (from n in db.Wall
                                       where (!n.IsSeen)
                                       && n.ToID == userID
                                       select n).FirstOrDefault();

                var newMessages = (from n in db.Message
                                   where (!n.IsSeen)
                                   && n.ToID == userID
                                   select n).FirstOrDefault();

                if (newfriends != null)
                    toReturn.Add("Friends", true);
                else
                    toReturn.Add("Friends", false);

                if (newWallMessages != null)
                    toReturn.Add("WallMessage", true);
                else
                    toReturn.Add("WallMessage", false);

                if (newMessages != null)
                    toReturn.Add("Messages", true);
                else
                    toReturn.Add("Messages", false);
            }
            return toReturn;
            
        }

        /// <summary>
        /// Gets the random users for display at startpage
        /// </summary>
        /// <param name="number"></param>
        /// <returns>List of ProfileComposites</returns>
        public List<ProfileComposite> GetRandomUsers(int number)
        {
            List<ProfileComposite> randomUsers = new List<ProfileComposite>();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var result = (from q in db.aspnet_Users
                                                 join p in db.Profile
                                                     on q.UserId equals p.UserID
                                                 select new { q.UserName, q.UserId, p.Gender })
                                                 .OrderBy(c => Guid.NewGuid()).Take(number);

                    
                       
                
                        foreach (var profile in result)
                        {
                            string username = GetUserName(profile.UserId);
                            ProfileComposite p = new ProfileComposite();
                            p.UserID = profile.UserId;
                            p.Username = username;
                            p.Gender = profile.Gender;

                            randomUsers.Add(p);
                        
                    }
                    return randomUsers;
                }
                catch
                {
                    return null;
                }
              }
        }

        /// <summary>
        /// Gets the username from a Guid
        /// </summary>
        /// <param name="userID"></param>
        /// <returns>String which holds the name of the user</returns>
        public string GetUserName(Guid userID)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var username = (from u in db.aspnet_Users
                                    where u.UserId == userID
                                    select u.UserName).SingleOrDefault();

                    return username.ToString();
                }
                catch {
                    return null;
                }
            }
        }

        /// <summary>
        /// Gets the previous transactions (premium buys) from a specified user
        /// </summary>
        /// <param name="userID"></param>
        /// <returns>An IEnumerable collection of TransactionComposite objects</returns>
        public IEnumerable<TransactionComposite> GetPremiumHistory(Guid userID)
        {
            List<TransactionComposite> history = new List<TransactionComposite>();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var result = (from transactions in db.Transaction
                                  where transactions.UserID == userID
                                  select new
                                  {
                                      transactions.UserID,
                                      transactions.TransactionDate,
                                      transactions.CardNumberLastDigits
                                  });


                    foreach (var transaction in result)
                    {
                        TransactionComposite t = new TransactionComposite();
                        t.TransactionDate = transaction.TransactionDate.ToShortDateString();
                        t.CardNumberLastDigits = transaction.CardNumberLastDigits;

                        history.Add(t);
                    }
                    return history;
                }
                catch
                {
                    return null;
                }
            }
            
        }

        /// <summary>
        /// Creates a new transaction and stores it in the database
        /// </summary>
        /// <param name="cardNumber"></param>
        /// <param name="userID"></param>
        /// <returns>True on success</returns>
        public bool CreateTransaction(string cardNumber, Guid userID)
        {
            // Check account balance here. On success:

            //Encrypts the cardnumber
            int salt = CardSalt.CreateRandomSalt();
            CardSalt saltedCardNumber = new CardSalt(cardNumber, salt);
            string hashedNumber = saltedCardNumber.ComputeSaltedHash();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    Transaction t = new Transaction();
                    t.CardNumber = hashedNumber;
                    t.CardNumberLastDigits = cardNumber.Substring(12);
                    t.CardSalt = salt.ToString();
                    t.TransactionDate = DateTime.Now;
                    t.UserID = userID;

                    db.Transaction.AddObject(t);

                    Profile p = (from profiles in db.Profile
                                 where profiles.UserID == userID
                                 select profiles).Single();

                    p.IsPremium = true;
                    p.PremiumExpireDate = DateTime.Now.AddMonths(1);

                    db.SaveChanges();
                    return true;
                }
                catch {
                    return false;
                }
            }
        }

        /// <summary>
        /// A search method that looks for users based on userdata and interests
        /// </summary>
        /// <param name="userData"></param>
        /// <param name="interests"></param>
        /// <param name="userSearching"></param>
        /// <returns>A list of ProfileComposite objects that matches the search criterias</returns>
        public List<ProfileComposite> SearchUsers(ProfileComposite userData, IEnumerable<int> interests, Guid userSearching)
        {
            string gender = userData.Gender; // is "m", "f" or null

            List<ProfileComposite> searchResults = new List<ProfileComposite>();

            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    // Search by user data
                    var userDataSearchResult = (from n in db.Profile
                                                join u in db.aspnet_Users
                                                on n.UserID equals u.UserId
                                                where
                                                  n.FirstName.Contains(userData.FirstName)
                                                  && n.LastName.Contains(userData.LastName)
                                                  && u.UserName.Contains(userData.Username)
                                                  && n.IsVisible == true
                                                  && u.UserId != userSearching
                                                select new
                                                {
                                                    n.UserID,
                                                    n.FirstName,
                                                    n.LastName,
                                                    n.IsPremium,
                                                    n.City,
                                                    n.Country,
                                                    n.BirthDate,
                                                    u.UserName,
                                                    n.Gender
                                                });
                    // Get UserInterest table
                    var userInterest = db.UserInterest.AsQueryable<UserInterest>();

                    // Is any interest(s) selected?
                    if (interests.Count() > 0)
                    {
                        foreach (int i in interests)
                        {
                            // Get all users with current interest
                            userInterest = from user in userInterest
                                           where i == (user.InterestID)
                                           select user;
                        }
                        foreach (var user in userInterest)
                        {
                            var filterUsersByInterest = userDataSearchResult.Where(x => x.UserID == user.UserID).SingleOrDefault();
                            if (gender != null)
                                filterUsersByInterest = userDataSearchResult.Where(x => x.UserID == user.UserID && x.Gender == gender).SingleOrDefault();

                            if (filterUsersByInterest != null)
                            {

                                ProfileComposite p = new ProfileComposite();
                                p.FirstName = filterUsersByInterest.FirstName;
                                p.LastName = filterUsersByInterest.LastName;
                                p.UserID = filterUsersByInterest.UserID;
                                p.IsPremium = filterUsersByInterest.IsPremium;
                                p.BirthDate = filterUsersByInterest.BirthDate.GetValueOrDefault(new DateTime(1901, 1, 1));
                                p.Username = filterUsersByInterest.UserName;

                                searchResults.Add(p);
                            }
                        }
                    }
                    else
                    // No interest criteria
                    {
                        if (gender != null)
                            userDataSearchResult = userDataSearchResult.Where(x => x.Gender == gender);

                        foreach (var user in userDataSearchResult)
                        {
                            ProfileComposite p = new ProfileComposite();
                            p.FirstName = user.FirstName;
                            p.LastName = user.LastName;
                            p.Username = user.UserName;
                            p.UserID = user.UserID;
                            p.IsPremium = user.IsPremium;
                            p.BirthDate = user.BirthDate.GetValueOrDefault(new DateTime(1901, 1, 1));
                            p.Gender = user.Gender;

                            searchResults.Add(p);
                        }
                    }
                }
                catch
                {
                    return null;
                }
                return searchResults;
            }
        }

        /// <summary>
        /// Gets all the users except the one that does the search.
        /// </summary>
        /// <param name="me">user searching</param>
        /// <returns>List of ProfileComposite objects with all other users</returns>
        public List<ProfileComposite> GetAllUsersExceptMe(Guid me)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                List<ProfileComposite> allUsersExceptMe = (from profile in db.Profile
                                                           join u in db.aspnet_Users
                                                           on (Guid)profile.UserID equals (Guid)u.UserId
                                                           where u.UserId != me
                                                           && profile.IsVisible == true
                                                           select new ProfileComposite
                                                           {
                                                               //BirthDate = (DateTime)profile.BirthDate,
                                                               FirstName = profile.FirstName,
                                                               LastName = profile.LastName,
                                                               Username = u.UserName,
                                                               UserID = u.UserId
                                                           }
                                 ).ToList();
                return allUsersExceptMe;
            }
        }

        /// <summary>
        /// Gets the result from the "click contest" on premium page
        /// </summary>
        /// <returns>A list of ClickHighScoreComposites with info on the score and the user scoring</returns>
        public List<ClickHighscoreComposite> getHighscore()
        {
            List<ClickHighscoreComposite> highscore = new List<ClickHighscoreComposite>();
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                try
                {
                    var result = (from i in db.ClickHighscore
                                  join users in db.aspnet_Users
                                  on i.UserID equals users.UserId
                                  orderby i.Highscore descending
                                  select new
                                   {
                                       i.UserID,
                                       i.Highscore,
                                       users.UserName
                                   });
                    int count = 1;
                    foreach (var item in result)
                    {
                        ClickHighscoreComposite h = new ClickHighscoreComposite();
                        h.UserID = item.UserID;
                        h.Highscore = item.Highscore;
                        h.UserName = item.UserName;
                        h.Place = count;
                        highscore.Add(h);
                        count++;
                    }

                    return highscore;
                }
                catch {
                    return null;
                }
            }
        }

        /// <summary>
        /// Adds a new highscore to the database
        /// </summary>
        /// <param name="user"></param>
        /// <param name="highscore"></param>
        /// <returns>true on success</returns>
        public bool AddNewHighscore(Guid user, int highscore)
        {
            using (GeekMeetEntities db = new GeekMeetEntities())
            {
                //Checks if the user already is in the highscorelist, if not - create a new highscore
                if (db.ClickHighscore.Any(u => u.UserID == user))
                {
                    ClickHighscore h = (from i in db.ClickHighscore
                                                        where i.UserID == user
                                                        select i).Single();
                    //Check if the new score is higher than the old one, if so - store it.
                    if (highscore > h.Highscore)
                    {
                        h.Highscore = highscore;
                        db.SaveChanges();
                        return true;
                    }
                }
                else
                {
                    ClickHighscore h = new ClickHighscore();
                    h.UserID = user;
                    h.Highscore = highscore;
                    db.ClickHighscore.AddObject(h);
                    db.SaveChanges();
                }
                return false;
            }
        }
    }
}
